package im.zego.zimexample;

import android.app.Activity;
import android.app.Application;
import android.content.Context;
import android.util.Log;

import org.json.JSONException;
import org.json.JSONObject;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.Set;

import im.zego.zim.ZIM;
import im.zego.zim.callback.ZIMEventHandler;
import im.zego.zim.callback.ZIMLogUploadedCallback;
import im.zego.zim.callback.ZIMLoggedInCallback;
import im.zego.zim.callback.ZIMMemberQueriedCallback;
import im.zego.zim.callback.ZIMMessageQueriedCallback;
import im.zego.zim.callback.ZIMMessageSentCallback;
import im.zego.zim.callback.ZIMRoomCreatedCallback;
import im.zego.zim.callback.ZIMRoomJoinedCallback;
import im.zego.zim.callback.ZIMRoomLeftCallback;
import im.zego.zim.callback.ZIMRoomOnlineMemberCountQueriedCallback;
import im.zego.zim.callback.ZIMTokenRenewedCallback;
import im.zego.zim.entity.ZIMError;
import im.zego.zim.entity.ZIMLogConfig;
import im.zego.zim.entity.ZIMMessage;
import im.zego.zim.entity.ZIMQueryMemberConfig;
import im.zego.zim.entity.ZIMQueryMessageConfig;
import im.zego.zim.entity.ZIMRoomInfo;
import im.zego.zim.entity.ZIMTextMessage;
import im.zego.zim.entity.ZIMUserInfo;
import im.zego.zim.enums.ZIMConnectionEvent;
import im.zego.zim.enums.ZIMConnectionState;
import im.zego.zim.enums.ZIMRoomEvent;
import im.zego.zim.enums.ZIMRoomState;
import im.zego.zimexample.util.AppLogger;
import im.zego.zimexample.util.TokenServerAssistant;
import im.zego.zimexample.util.debug.log.FloatingView;

public class SDKManager {

    private static SDKManager sdkManager;
    private String TAG = "SDKManager";
    public Context context;
    private OnLoginStateCallback mLoginStateCallback;
    private OnRoomMemberLeftCallback memberLeftCallback;
    ZIMUserInfo zimUserInfo = new ZIMUserInfo();
    private Set<OnRoomStateCallback> onRoomStateChangedList = new HashSet<>();
    private Set<OnReceiveRoomMessage> onReceiveRoomMessageList = new HashSet<>();
    private Set<OnReceivePeerMessage> onReceivePeerMessageList = new HashSet<>();
    private OnTokenCallback tokenCallback;

    private ZIM zim;

    public static SDKManager sharedInstance() {
        if (sdkManager == null) {
            synchronized (SDKManager.class) {
                if (sdkManager == null) {
                    sdkManager = new SDKManager();
                }
            }
        }
        return sdkManager;
    }


    public void create(Application application) {
        this.context = application;
        ZIMLogConfig zimLogConfig = new ZIMLogConfig();
        zimLogConfig.logSize = 50 * 1000;
        ZIM.setLogConfig(zimLogConfig);
        zim = ZIM.create(KeyCenter.appID, application);

        zim.setEventHandler(new ZIMEventHandler() {
            @Override
            public void onError(ZIM zim, ZIMError errorCode) {
                Log.e(TAG, "errorCode:" + errorCode);
                AppLogger.getInstance().d("[%s] [onError] [ZIMErrorCode:%s]", TAG, errorCode);
            }

            @Override
            public void onConnectionStateChanged(ZIM zim, ZIMConnectionState state, ZIMConnectionEvent event, JSONObject extendedData) {
                Log.e(TAG, "onConnectionStateChanged:" + state.name());
                if (mLoginStateCallback != null) {
                    mLoginStateCallback.onConnectionStateChanged(zim, state, event, extendedData);
                }
                AppLogger.getInstance().d("[%s] [onConnectionStateChanged] [state:%s]", TAG, state.name());
            }

            @Override
            public void onRoomStateChanged(ZIM zim, ZIMRoomState state, ZIMRoomEvent event, JSONObject extendedData, String roomID) {
                AppLogger.getInstance().d("[%s] [onRoomStateChanged] [state:%s, event:%s]", TAG, state.name(), event.name());
                for (final OnRoomStateCallback callback : onRoomStateChangedList) {
                    if (callback != null) {
                        callback.onRoomStateChanged(zim, state, event, extendedData);
                    }
                }
            }

            @Override
            public void onReceiveRoomMessage(ZIM zim, ArrayList<ZIMMessage> messageList, String fromRoomID) {
                for (final OnReceiveRoomMessage callback : onReceiveRoomMessageList) {
                    if (callback != null) {
                        callback.onReceiveRoomMessage(zim, messageList, fromRoomID);
                    }
                }
                for (ZIMMessage zimMessage : messageList) {
                    if (zimMessage instanceof ZIMTextMessage) {
                        AppLogger.getInstance().d("[%s] [onReceiveRoomMessage] [userID:%s, message:%s, priority:%s]", TAG, zimMessage.userID, ((ZIMTextMessage) zimMessage).message, zimMessage.priority.name());
                    }
                }
            }

            @Override
            public void onRoomMemberLeft(ZIM zim, ArrayList<ZIMUserInfo> memberList, final String roomID) {
                Log.e(TAG, "onRoomMemberLeft:" + roomID);
                ZIMQueryMemberConfig zimQueryMemberConfig = new ZIMQueryMemberConfig();
                zimQueryMemberConfig.count = 100;
                for (ZIMUserInfo zimUserInfo : memberList) {
                    AppLogger.getInstance().d("[%s] [onRoomMemberLeft] [roomID:%s, userID:%s]", TAG, roomID, zimUserInfo.userID);
                }
                if (memberLeftCallback != null) {
                    memberLeftCallback.onRoomMemberLeft(zim, memberList, roomID);
                }

            }

            @Override
            public void onReceivePeerMessage(ZIM zim, ArrayList<ZIMMessage> messageList, String fromUserID) {
                for (ZIMMessage zimMessage : messageList) {
                    if (zimMessage instanceof ZIMTextMessage) {
                        AppLogger.getInstance().d("[%s] [onReceivePeerMessage] [userID:%s, message:%s, priority:%s]", TAG, zimMessage.userID, ((ZIMTextMessage) zimMessage).message, zimMessage.priority.name());
                    }
                }

                for (final OnReceivePeerMessage callback : onReceivePeerMessageList) {
                    if (callback != null) {
                        callback.onReceivePeerMessage(zim, messageList, fromUserID);
                    }
                }
            }

            @Override
            public void onRoomMemberJoined(ZIM zim, ArrayList<ZIMUserInfo> memberList, final String roomID) {
                ZIMQueryMemberConfig zimQueryMemberConfig = new ZIMQueryMemberConfig();
                zimQueryMemberConfig.count = 100;
                zim.queryRoomMember(roomID, zimQueryMemberConfig, new ZIMMemberQueriedCallback() {
                    @Override
                    public void onMemberQueried(ArrayList<ZIMUserInfo> arrayList, String s, ZIMError zimErrorCode) {
                        AppLogger.getInstance().d("[%s] [memberNumber] [roomID:%s, memberNumber: %d]", TAG, roomID, arrayList.size());
                    }
                });
                for (ZIMUserInfo zimUserInfo : memberList) {
                    AppLogger.getInstance().d("[%s] [onRoomMemberJoined] [roomID:%s, userID:%s ]", TAG, roomID, zimUserInfo.userID);
                }
            }

            @Override
            public void onTokenWillExpire(ZIM zim, int second) {
                super.onTokenWillExpire(zim, second);
                if (tokenCallback != null) {
                    tokenCallback.OnTokenWillExpire(zim, second);
                }
                AppLogger.getInstance().d("[%s] [onTokenWillExpire] [second:%d]", TAG, second);
                try {
                    AppLogger.getInstance().d("[%s] [renewToken] [second:%d]", TAG, second);
                    zim.renewToken(TokenServerAssistant.generateToken(KeyCenter.appID, zimUserInfo.userID, KeyCenter.secret, 60 * 60 * 24).data, new ZIMTokenRenewedCallback() {
                        @Override
                        public void onTokenRenewed(String s, ZIMError zimError) {
                            AppLogger.getInstance().d("[%s] [onTokenRenewed] [zimErrorCode:%s]", TAG, zimError.code.name());
                        }
                    });
                } catch (JSONException e) {
                    e.printStackTrace();
                }
            }

        });

        zim.queryRoomOnlineMemberCount("", new ZIMRoomOnlineMemberCountQueriedCallback() {
            @Override
            public void onRoomOnlineMemberCountQueried(int memberCount, ZIMError zimError) {

            }
        });

    }


    public void createRoom(String roomID, String roomName, ZIMRoomCreatedCallback callback) {
        if (zim == null) {
            AppLogger.getInstance().d("[%s] [createRoom] [zim = null]", TAG);
            return;
        }
        ZIMRoomInfo zimRoomInfo = new ZIMRoomInfo();
        zimRoomInfo.roomID = roomID;
        zimRoomInfo.roomName = roomName;
        zim.createRoom(zimRoomInfo, callback);
        AppLogger.getInstance().d("[%s] [createRoom roomID:%s, roomName:%s]", TAG, roomID, roomName);
    }

    public void upload() {
        zim.uploadLog(new ZIMLogUploadedCallback() {
            @Override
            public void onLogUploaded(ZIMError zimErrorCode) {
                AppLogger.getInstance().d("[%s] [onLogUploaded zimErrorCode:%s]", TAG, zimErrorCode.code.name());
            }
        });
    }

    // 登出
    public void logout() {
        if (zim == null) {
            AppLogger.getInstance().d("[%s] [logout] [zim = null]", TAG);
            return;
        }
        AppLogger.getInstance().d("[%s] [logout]", TAG);
        zim.logout();
    }

    // 登录房间
    public void logoutRoom(final String roomID) {
        if (zim == null) {
            AppLogger.getInstance().d("[%s] [logoutRoom] [zim = null]", TAG);
            return;
        }
        AppLogger.getInstance().d("[%s] [logoutRoom] [roomID:%s]", TAG, roomID);
        zim.leaveRoom(roomID, new ZIMRoomLeftCallback() {
            @Override
            public void onRoomLeft(ZIMError zimError) {
                AppLogger.getInstance().d("[%s] [onRoomLeft] [roomID:%s]", TAG, roomID);
            }
        });
    }

    public void joinRoom(String roomID, ZIMRoomJoinedCallback callback) {
        if (zim == null) {
            AppLogger.getInstance().d("[%s] [joinRoom] [zim = null]", TAG);
            return;
        }
        AppLogger.getInstance().d("[%s] [joinRoom roomID:%s]", TAG, roomID);
        zim.joinRoom(roomID, callback);
    }


    public void queryPeerMessage(String userID, long messageID, int count, boolean reverse, final ZIMMessageQueriedCallback zimMessageQueriedCallback) {
        if (zim == null) {
            AppLogger.getInstance().d("[%s] [getUserSessionMsg] [zim = null]", TAG);
            return;
        }
        ZIMQueryMessageConfig zimQueryMessageConfig = new ZIMQueryMessageConfig();
        zimQueryMessageConfig.messageID = messageID;
        zimQueryMessageConfig.count = count;
        zimQueryMessageConfig.reverse = reverse;
        zim.queryPeerMessage(userID, zimQueryMessageConfig, new ZIMMessageQueriedCallback() {
            @Override
            public void onMessageQueried(ArrayList<ZIMMessage> arrayList, ZIMError zimErrorCode) {
                if (zimMessageQueriedCallback != null) {
                    zimMessageQueriedCallback.onMessageQueried(arrayList, zimErrorCode);
                }
            }
        });
    }


    public void login(String userID, String userName, String token, ZIMLoggedInCallback callback) {
        if (zim == null) {
            AppLogger.getInstance().d("[%s] [login] [zim = null]", TAG);
            return;
        }
        try {
            if (token == null || "".equals(token)) {
                token = TokenServerAssistant.generateToken(KeyCenter.appID, userID, KeyCenter.secret, 60 * 60 * 24).data;
            }
            AppLogger.getInstance().d("[%s] [login] [userID:%s token:%s]", TAG, userID, token);
            zimUserInfo.userID = userID;
            zimUserInfo.userName = userName;
            zim.login(zimUserInfo, token, callback);


        } catch (JSONException e) {
            e.printStackTrace();
        }
    }

    public void sendRoomMsg(ZIMMessage msg, String roomID, ZIMMessageSentCallback callback) {
        if (zim == null) {
            AppLogger.getInstance().d("[%s] [sendRoomMsg] [zim = null]", TAG);
            return;
        }
        if (msg instanceof ZIMTextMessage) {
            AppLogger.getInstance().d("[%s] [sendRoomMsg] [userID:%s msg:%s]", TAG, roomID, ((ZIMTextMessage) msg).message);
        }
        zim.sendRoomMessage(msg, roomID, callback);
    }

    public void sendMsg(ZIMMessage msg, String userID, ZIMMessageSentCallback callback) {
        if (zim == null) {
            AppLogger.getInstance().d("[%s] [sendMsg] [zim = null]", TAG);
            return;
        }
        if (msg instanceof ZIMTextMessage) {
            AppLogger.getInstance().d("[%s] [sendMsg] [userID:%s msg:%s]", TAG, userID, ((ZIMTextMessage) msg).message);
        }
        zim.sendPeerMessage(msg, userID, callback);

    }


    public void queryMember(String roomID, ZIMQueryMemberConfig config, ZIMMemberQueriedCallback callback) {
        if (zim == null) {
            AppLogger.getInstance().d("[%s] [queryMember] [zim = null]", TAG);
            return;
        }
        zim.queryRoomMember(roomID, config, callback);
    }

    public void queryRoomOnlineMemberCount(String roomID, ZIMRoomOnlineMemberCountQueriedCallback callback) {
        if (zim == null) {
            AppLogger.getInstance().d("[%s] [queryRoomOnlineMemberCount] [zim = null]", TAG);
            return;
        }
        AppLogger.getInstance().d("[%s] [queryRoomOnlineMemberCount] [roomID:%s]", TAG, roomID);
        zim.queryRoomOnlineMemberCount(roomID, callback);
    }


    public void setRoomMemberLeftCallback(OnRoomMemberLeftCallback onRoomMemberLeftCallback) {
        memberLeftCallback = onRoomMemberLeftCallback;
    }

    public void addReceivePeerMessageCallback(OnReceivePeerMessage callback) {
        onReceivePeerMessageList.add(callback);
    }

    public void removeReceivePeerMessageCallback(OnReceivePeerMessage callback) {
        onReceivePeerMessageList.remove(callback);
    }

    public void addReceiveRoomMessageCallback(OnReceiveRoomMessage callback) {
        onReceiveRoomMessageList.add(callback);
    }

    public void removeReceiveRoomMessageCallback(OnReceiveRoomMessage callback) {
        onReceiveRoomMessageList.remove(callback);
    }

    public void addRoomStateChangedCallback(OnRoomStateCallback callback) {
        onRoomStateChangedList.add(callback);
    }

    public void removeRoomStateChangedCallback(OnRoomStateCallback callback) {
        onRoomStateChangedList.remove(callback);
    }

    public interface OnTokenCallback {
        void OnTokenWillExpire(ZIM zim, int second);
    }

    public interface OnRoomStateCallback {
        void onRoomStateChanged(ZIM zim, ZIMRoomState state, ZIMRoomEvent event, JSONObject extendedData);
    }

    public interface OnLoginStateCallback {
        void onConnectionStateChanged(ZIM zim, ZIMConnectionState state, ZIMConnectionEvent event, JSONObject extendedData);
    }

    public interface OnRoomMemberLeftCallback {
        void onRoomMemberLeft(ZIM zim, ArrayList<ZIMUserInfo> memberList, final String roomID);
    }

    public interface OnReceivePeerMessage {
        void onReceivePeerMessage(ZIM zim, ArrayList<ZIMMessage> messageList, String fromUserID);
    }

    public interface OnReceiveRoomMessage {
        void onReceiveRoomMessage(ZIM zim, ArrayList<ZIMMessage> messageList, String fromRoomID);
    }

    public void destroy() {
        if (zim == null) {
            AppLogger.getInstance().d("[%s] [destroy] [zim = null]", TAG);
            return;
        }
        AppLogger.getInstance().d("[%s] [destroy]", TAG);
        zim.destroy();
        zim = null;
    }


    public void showDebugLog(Activity activity) {
        FloatingView.get().attach(activity);
        FloatingView.get().add();
    }

    public void closeDebugLog(Activity activity) {
        FloatingView.get().detach(activity);

    }

}
